```vue
<script setup>
import { ref, watch } from 'vue';
import { useRoute, useRouter, onBeforeRouteUpdate } from 'vue-router';
import { useCookies } from '@vueuse/integrations/useCookies';
import { useUserInfoStore } from '@/stores/userInfo.js';
import { getClassById } from '@/api/manager.js';
import { ElMessage } from 'element-plus';
import { useChangeTab } from '@/utils/routerUtils.js';

const route = useRoute();
const router = useRouter();
const store = useUserInfoStore();
const cookie = useCookies();
const classData = ref({});
const classCache = ref({});
const activeTab = ref(route.path.includes('/classDetails/') ? `/educational/classManagement/classDetails/${route.params.id}` : route.path);
const { changeTab } = useChangeTab(activeTab); // 导入 changeTab

const tabList = ref([
  {
    title: '后台首页',
    path: '/',
  },
  {
    title: '班级管理',
    path: '/educational/classManagement/class',
  },
]);

const excludedRoutes = [
  'schedule',
  'completed',
  'attendance',
  'students',
];

async function fetchClassDetails(classId) {
  if (classCache.value[classId]) {
    classData.value[classId] = classCache.value[classId];
    return classData.value[classId];
  }
  try {
    const res = await getClassById(classId);
    console.log('班级详情响应:', res);
    if (res.code === 200) {
      classCache.value[classId] = res.detail;
      classData.value[classId] = res.detail;
      return res.detail;
    }
    return null;
  } catch (error) {
    console.error('获取班级详情失败:', error);
    ElMessage.error('获取班级详情失败');
    return null;
  }
}

async function addTab(tab) {
  const isExcluded = excludedRoutes.some(route => tab.path.includes(`/${route}`));
  if (isExcluded) {
    console.log('排除子路由:', tab.path);
    return;
  }

  let finalPath = tab.path;
  let finalTitle = tab.title;

  if (tab.path.includes('/classDetails/')) {
    const classId = tab.path.match(/\/classDetails\/([^/]+)/)?.[1];
    if (!classId || isNaN(classId)) {
      console.error('无效的班级 ID:', tab.path);
      ElMessage.error('无效的班级 ID，无法添加标签');
      return;
    }
    const data = await fetchClassDetails(classId);
    finalTitle = data ? data.className : `班级详情 (${classId})`;
    finalPath = `/educational/classManagement/classDetails/${classId}`;
  }

  const existingTab = tabList.value.find(t => t.path === finalPath);
  if (!existingTab) {
    tabList.value.push({ title: finalTitle, path: finalPath });
    cookie.set('tabList', tabList.value);
    console.log('添加Tab:', { title: finalTitle, path: finalPath }, '当前Tab列表:', tabList.value);
  }
}

function initTabList() {
  const tbs = cookie.get('tabList');
  if (tbs) {
    tabList.value = tbs.filter(tab => !excludedRoutes.some(route => tab.path.includes(`/${route}`)));
    console.log('初始化Tab列表:', tabList.value);
  }
}
initTabList();

onBeforeRouteUpdate(async (to) => {
  const isDetailPage = to.path.includes('/classDetails/');
  const classId = to.params.id;
  let tab = {
    title: to.meta.title || '未命名',
    path: to.path,
  };

  if (isDetailPage) {
    if (!classId) {
      console.error('详情页缺少 classId:', to.path);
      ElMessage.error('无效的班级 ID');
      return;
    }
    const data = await fetchClassDetails(classId);
    tab = {
      title: data ? data.className : `班级详情 (${classId})`,
      path: `/educational/classManagement/classDetails/${classId}`,
    };
  }

  activeTab.value = tab.path;
  await addTab(tab);
});

watch(
    () => route.path,
    (newPath) => {
      const isDetailPage = newPath.includes('/classDetails/');
      if (isDetailPage) {
        const classId = newPath.match(/\/classDetails\/([^/]+)/)?.[1];
        if (classId) {
          activeTab.value = `/educational/classManagement/classDetails/${classId}`;
        }
      } else if (!excludedRoutes.some(route => newPath.includes(`/${route}`))) {
        activeTab.value = newPath;
      }
    },
    { immediate: true }
);

const removeTab = (path) => {
  let tabs = tabList.value;
  let a = activeTab.value;
  if (a === path) {
    tabs.forEach((tab, index) => {
      if (tab.path === path) {
        const nextTab = tabs[index + 1] || tabs[index - 1];
        if (nextTab) {
          a = nextTab.path;
        }
      }
    });
  }
  activeTab.value = a;
  tabList.value = tabs.filter(tab => tab.path !== path);
  cookie.set('tabList', tabList.value);
  console.log('移除Tab后新列表:', tabList.value);
  if (route.path === path || route.path.startsWith(path)) {
    router.push(a).catch(err => {
      console.error('移除Tab后跳转失败:', err, '目标路径:', a);
      ElMessage.error('跳转失败，请检查路由配置');
    });
  }
};

const handleClose = (c) => {
  if (c === 'clearAll') {
    activeTab.value = '/';
    tabList.value = [{ title: '后台首页', path: '/' }];
    router.push('/').catch(err => {
      console.error('清空Tab跳转失败:', err);
      ElMessage.error('跳转失败');
    });
  } else if (c === 'clearOther') {
    tabList.value = tabList.value.filter(tab => tab.path === '/' || tab.path === activeTab.value);
    cookie.set('tabList', tabList.value);
    console.log('关闭其他后Tab列表:', tabList.value);
  }
};
</script>

<template>
  <div class="f-tag-list" :style="{ left: store.asideWidth }">
    <el-tabs
        v-model="activeTab"
        type="card"
        class="demo-tabs"
        closable
        @tab-remove="removeTab"
        @tab-change="changeTab"
        style="min-width: 100px"
    >
      <el-tab-pane
          v-for="item in tabList"
          :key="item.path"
          :label="item.title"
          :name="item.path"
      />
    </el-tabs>
    <span class="tag-btn">
      <el-dropdown @command="handleClose">
        <span class="el-dropdown-link">
          <el-icon><arrow-down /></el-icon>
        </span>
        <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item command="clearOther">关闭其他</el-dropdown-item>
            <el-dropdown-item command="clearAll">全部关闭</el-dropdown-item>
          </el-dropdown-menu>
        </template>
      </el-dropdown>
    </span>
  </div>
  <div style="height: 44px"></div>
</template>

<style scoped>
.f-tag-list {
  @apply fixed bg-gray-100 flex items-center px-2;
  top: 64px;
  right: 0;
  height: 44px;
  z-index: 100;
}

.tag-btn {
  @apply bg-white rounded ml-auto flex items-center justify-center px-2;
  height: 32px;
  width: 32px;
}

:deep(.el-tabs__header) {
  @apply mb-0;
  border: 0 !important;
}

:deep(.el-tabs__nav) {
  border: 0 !important;
}

:deep(.el-tabs__item) {
  border: 0 !important;
  height: 32px;
  line-height: 32px;
  @apply mx-1 bg-white rounded;
}

:deep(.el-tabs__nav-next),
:deep(.el-tabs__nav-prev) {
  line-height: 32px;
  height: 32px;
}

:deep(.is-disabled) {
  cursor: not-allowed;
  @apply text-gray-400;
}

:deep(.el-tabs__item.is-active) {
  @apply bg-blue-500 text-white;
}
</style>
```